package org.zjx.core;

import lombok.Data;
import org.zjx.algorithm.PathFindingStrategy;
import org.zjx.entity.Location;
import org.zjx.factory.RouteFactory;
import org.zjx.model.route.Route;
import org.zjx.pojo.RouteQueryPojo;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 核心路由管理类
 * 职责：
 * 1. 整合静态路由和玩家动态路由
 * 2. 管理路径查找流程
 * 3. 提供高级查询接口
 */
@Data
public class RouteManager {
    private final CacheManager cacheManager;
    private final PathFindingStrategy pathFinder;
    private final RouteFactory routeFactory;

    public RouteManager(PathFindingStrategy pathFinder,
                        RouteFactory routeFactory) {
        this.pathFinder = Objects.requireNonNull(pathFinder);
        this.routeFactory = Objects.requireNonNull(routeFactory);

        RouteGraphLoader loader = new RouteGraphLoader(routeFactory);
        this.cacheManager = new CacheManager(loader.loadStaticGraph(), this, routeFactory);

    }

    /**
     * 查找完整路径（自动处理动态路由）
     *
     * @param routeQueryPojo 玩家数据（包含起点/终点/道具等）
     * @return 最优路径，null表示不可达
     */
    public List<Route> findPath(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = buildCompleteGraph(routeQueryPojo);
        return pathFinder.findPath(graph, routeQueryPojo.getStart().toLocation(), routeQueryPojo.getEnd().toLocation());
    }

    /**
     * 查找满足时间限制的路径
     *
     * @param routeQueryPojo 玩家数据
     * @param maxTimeSeconds 最大允许耗时（秒）
     * @return 符合条件的路径
     */
    public List<Route> findPathWithinTime(RouteQueryPojo routeQueryPojo, int maxTimeSeconds) {
        RouteGraph graph = buildCompleteGraph(routeQueryPojo);
        return pathFinder.findPathWithinTime(
                graph, routeQueryPojo.getStart().toLocation(), routeQueryPojo.getEnd().toLocation(), maxTimeSeconds);
    }

    /**
     * 构建完整路由图（静态+动态）
     */
    private RouteGraph buildCompleteGraph(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = new RouteGraph(cacheManager.getPlayerGraph(routeQueryPojo));
        Location start = routeQueryPojo.getStart().toLocation();
        Location end = routeQueryPojo.getEnd().toLocation();

        // 新增：同场景时直接连接起点和终点
        if (start.sameScene(end)) {
            boolean indoor = start.isRoom();
            if (!hasRouteBetween(graph,start, end)) {
                graph.addRoute(routeFactory.createRunningRoute(start, end, indoor));
            }
        } else {
            // 跨场景时连接起点/终点到传送点
            connectSpecialLocations(graph, start, false);
            connectSpecialLocations(graph, end, true);
        }
        return graph;
    }

    /**
     * 连接特殊位置（起点/终点）的同场景路由
     */
    public void connectSpecialLocations(RouteGraph graph, Location location, boolean reverse) {

        // 1. 收集所有传送点的起点（本场景的传送起点）
        Set<Location> transferStartPoints = graph.getAllLocations().stream()
                .filter(loc -> graph.getRoutesFrom(loc).stream().anyMatch(route -> route.getType().isTransfer()))
                .filter(loc -> loc.sameScene(location))
                .collect(Collectors.toSet());

        // 2. 收集所有传送点的终点（其他场景传送过来的落脚点）
        Set<Location> transferEndPoints = graph.getAdjacencyMap().values().stream()
                .flatMap(List::stream)
                .filter(route -> route.getType().isTransfer() && route.getEnd().sameScene(location))
                .map(Route::getEnd)
                .collect(Collectors.toSet());

        if (!reverse) {
            for (Location startLocation : transferStartPoints) {
                boolean indoor = location.isRoom();
                if (hasRouteBetween(graph, location, startLocation)) continue;
                graph.addRoute(routeFactory.createRunningRoute(location, startLocation, indoor));
            }
        } else {
            for (Location endLocation : transferEndPoints) {
                boolean indoor = location.isRoom();
                if (hasRouteBetween(graph, endLocation, location)) continue;
                graph.addRoute(routeFactory.createRunningRoute(endLocation, location, indoor));
            }
        }
    }

    /**
     * 检查两个位置之间是否已有路由
     */
    private boolean hasRouteBetween(RouteGraph graph, Location from, Location to) {
        return graph.getRoutesFrom(from).stream()
                .anyMatch(route -> route.getEnd().equals(to));
    }

    /**
     * 计算路径总耗时
     */
    public static int calculateTotalTime(List<Route> path) {
        return PathFindingStrategy.getTotalTime(path);
    }
}